// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; namespace LargoCommon.Music { /// /// Rhythmic Container. /// public class RhythmicContainer { #region Fields /// /// Singleton variable. /// private static readonly RhythmicContainer InternalSingleton = new RhythmicContainer(); #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// The given rhythmic structures. public RhythmicContainer(IEnumerable givenRhythmicStructures) { Contract.Requires(givenRhythmicStructures != null); this.RhythmicStructures = givenRhythmicStructures; } /// /// Prevents a default instance of the RhythmicContainer class from being created. /// private RhythmicContainer() { } #endregion #region Static properties /// /// Gets the ProcessLogger Singleton. /// /// Property description. /// public static RhythmicContainer Singleton { get { Contract.Ensures(Contract.Result() != null); if (InternalSingleton == null) { throw new InvalidOperationException("Singleton Rhythmic Container is null."); } return InternalSingleton; } } #endregion #region Public properties /// /// Gets the rhythmic structures. /// /// /// The rhythmic structures. /// public IEnumerable RhythmicStructures { get; } /// /// Gets or sets the rhythm of harmony structures. /// /// /// The rhythm of harmony structures. /// [UsedImplicitly] public IList RhythmicOfHarmonyStructures { get; set; } //// CA1044 (FxCop) #endregion #region Private properties /* /// /// Gets all variant structures. /// /// Property description. private IList AllVariantStructures { get { //// return null; ///// Rhythmic structures ... var structs = RegularStructures(this.rhythmicOrder).ToList(); structs.AddRange(this.Structures); structs.AddRange(this.RhythmicOfHarmonyStructures); var sortedStructs = (from str in structs orderby str.Mobility ascending, str.ElementSchema descending where str != null select str).Distinct().ToList(); return sortedStructs; } } /// /// Gets the common structures. /// /// Property description. private IList CommonStructures { get { var structs = this.SegmentOfStructures(3, 0); return structs; } } /// /// Gets the mean structures. /// /// Property description. private IList MeanStructures { get { var structs = this.SegmentOfStructures(3, 1); return structs; } } /// /// Gets the rare structures. /// /// Property description. private IList RareStructures { get { var structs = this.SegmentOfStructures(3, 2); return structs; } } /// /// Gets or sets the structures. /// /// /// The structures. /// private IList Structures { get; set; } */ #endregion #region Static methods /// /// Gets the regular structures. /// /// The given rhythmic order. /// /// Returns value. /// /// Property description. public static IList RegularStructures(byte givenRhythmicOrder) { var structs = new List(); for (var parts = 1; parts < givenRhythmicOrder - 1; parts++) { if (parts > 16 || givenRhythmicOrder % parts != 0) { continue; } var rms = RegularRhythmicStructure(givenRhythmicOrder, parts); structs.Add(rms); } return structs; } #endregion /// Gets grouped rhythmic structures. /// The given model. /// The given block. /// The grouped rhythmic structures. public IList GetGroupedRhythmicStructures(RhythmicModel givenModel, MusicalBlock givenBlock) { var rhythmicMaterial = givenModel.ExtractRhythmicMaterial(); var list = (from s in rhythmicMaterial.Structures orderby s.ToneLevel descending, s.FormalBehavior.Variance ascending, s.Occurrence descending select s).ToList(); //// Regular structures. var regular = RegularStructures(givenModel.RhythmicOrder); //// Header.System.RhythmicOrder list.AddRange(regular); //// Structures from harmony. if (givenBlock != null) { var tmplist = new List(); foreach (var bar in givenBlock.Body.Bars) { var structure = bar?.HarmonicBar?.RhythmicStructure; if (structure == null) { continue; } tmplist.Add(structure); } list.AddRange(tmplist); } //// Grouping IList structures = new List(); var groupList = (from ms in list group ms by ms.GetStructuralCode into g select g).ToList(); foreach (var g in groupList) { var s = g.FirstOrDefault(); if (s == null) { continue; } var ms = s; //// Clone? //// new RhythmicStructure(s.RhythmicSystem, s.GetStructuralCode()) ms.Occurrence = g.Count(); ms.DetermineLevel(); //// 2019/01 ms.DetermineBehavior(); //// 2019/01 structures.Add(ms); } return structures; } #region Public methods - Find rhythmic structures /// /// Rhythmic structure. /// /// The energy change. /// /// Returns value. /// [UsedImplicitly] public RhythmicStructure FindRhythmicStructure(EnergyChange energyChange) { RhythmicStructure optimalStructure = null; float bestValue = +10000; foreach (var structure in this.RhythmicStructures) { var value = Math.Abs(structure.Level - energyChange.BeatLevel) + Math.Abs(structure.ToneLevel - energyChange.ToneLevel) + Math.Abs(structure.FormalBehavior.Variance - energyChange.RhythmicTension); if (value >= bestValue) { continue; } bestValue = value; optimalStructure = structure; } return optimalStructure; } /// /// Finds the similar structure. /// /// The given struct. /// /// Returns value. /// [UsedImplicitly] public RhythmicStructure FindSimilarStructure(RhythmicStructure givenStruct) { Contract.Requires(givenStruct != null); RhythmicStructure optimalStruct = null; float minimumResult = 1000; //// rstruct.DetermineBehavior(); foreach (var rstruct in this.RhythmicStructures) { //// 1000 if (rstruct.ElementSchema == givenStruct.ElementSchema) { continue; } var s = rstruct.SimilarityValue(givenStruct); if (s > 90) { continue; } var level = givenStruct.Level + rstruct.Level > 0 ? 100.0f * 2 * Math.Abs(givenStruct.Level - rstruct.Level) / (givenStruct.Level + rstruct.Level) : 0; var toneLevel = givenStruct.ToneLevel + rstruct.ToneLevel > 0 ? 100.0f * 2 * Math.Abs(givenStruct.ToneLevel - rstruct.ToneLevel) / (givenStruct.ToneLevel + rstruct.ToneLevel) : 0; var variance = Math.Abs(givenStruct.FormalBehavior.Variance - rstruct.FormalBehavior.Variance); var balance = Math.Abs(givenStruct.FormalBehavior.Balance - rstruct.FormalBehavior.Balance); //// float beat = Math.Abs(givenStruct.Beat - rstruct.Beat); //// float filling = Math.Abs(givenStruct.Filling - rstruct.Filling); //// float complexity = Math.Abs(givenStruct.Complexity - rstruct.Complexity); var result = (4 * toneLevel) + (2 * level) + variance + balance; if (result >= minimumResult) { continue; } optimalStruct = rstruct; minimumResult = result; } return optimalStruct; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { return "RhythmicContainer"; } #endregion #region Public methods /// /// Gets the structures. /// /// /// Returns value. /// public IEnumerable GetStructures() { return null; /* Rhythmic structures ... var structures = new List(); switch (listIndex) { case 0: { structures = (List)this.AllVariantStructures; break; } case 1: { structures = (List)this.CommonStructures; break; } case 2: { structures = (List)this.MeanStructures; break; } case 3: { structures = (List)this.RareStructures; break; } case 4: { structures = (List)RegularStructures(this.rhythmicOrder); break; } case 5: { structures = (List)this.RhythmicOfHarmonyStructures; break; } } if (structures == null) { return null; } var distinctList = structures .GroupBy(s => s.ElementSchema) .Select(g => g.First()) .ToList(); var sortedList = (from s in distinctList orderby s.Level, s.ToneLevel select s).ToList(); return sortedList; */ } /// /// Prepares the rhythmic structures. /// /// The total number. /// If set to true [include inversions]. /// /// Returns value. /// [UsedImplicitly] public IList LeadingStructures(int totalNumber, bool includeInversions) { var structures = new List(); /* var number = 0; var commonStructs = LeadingStructures(totalNumber, includeInversions, this.CommonStructures, ref number); structures.AddRange(commonStructs); var meanStructs = LeadingStructures(totalNumber, includeInversions, this.MeanStructures, ref number); structures.AddRange(meanStructs); */ return structures; } #endregion #region Private static methods - Regular structures /// /// Regulars the rhythmic structure. /// /// The given rhythmic order. /// The parts. /// /// Returns value. /// private static RhythmicStructure RegularRhythmicStructure(byte givenRhythmicOrder, int parts) { var rs = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, givenRhythmicOrder); var sb = new StringBuilder(); var length = givenRhythmicOrder / parts; var s = string.Format(CultureInfo.CurrentCulture, "1,{0}*0,", length - 1); for (var i = 0; i < parts; i++) { sb.Append(s); } sb.Remove(sb.Length - 1, 1); var rms = new RhythmicStructure(rs, sb.ToString()); return rms; } #endregion #region Private methods /* /// /// Leading structures. /// /// The total number. /// If set to true [include inversions]. /// The common. /// The number. /// Returns value. private static IEnumerable LeadingStructures(int totalNumber, bool includeInversions, IList common, ref int number) { var structures = new List(); structures.AddRange(common.Take(number)); number += structures.Count; foreach (var rstruct in common) { // ReSharper disable once InvertIf if (includeInversions) { var invertedStructure = rstruct.InvertedStructure(); structures.Add(invertedStructure); if (number >= totalNumber) { break; } } } return structures; } /// /// Segments the of structures. /// /// The class count. /// The class number. /// Returns value. private List SegmentOfStructures(int classCount, int classNumber) { var modelStructs = this.Structures; var cnt = modelStructs.Count; var number = (int)(1.0f * cnt / classCount); var start = number * classNumber; var structs = (from str in modelStructs orderby str.Occurrence descending, str.Level ascending, str.ToneLevel ascending select str) .Skip(start) .Take(number).ToList(); return structs; } */ #endregion } }